/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 * Description: cann error status reporter
 * Author: huawei
 * Create: 2024-10-14
 */

#include "cann_error_reporter.h"
#include <cstdio>
#include "log.h"
#include "adapter_rts.h"
#include "dlhal_function.h"

namespace dfx {
constexpr uint32_t HCCL_ASSERT_EVENT_MASK = 0xE00; // 当前仅使能 bit 9-B
constexpr uint32_t  HCCL_DEASSERT_EVENT_MASK = 0x0; // 0x09/0x0A/0x0B 使能为通知事件

constexpr uint64_t DEFAULT_SENSOR_HANDLE = 0xFFFFFFFF;


CannErrorReporter::CannErrorReporter()
    : sensorHandle_(DEFAULT_SENSOR_HANDLE), devId_(0)
{
    if (!hccl::DlHalFunction::GetInstance().DlHalFunctionIsInit() &&
        hccl::DlHalFunction::GetInstance().DlHalFunctionInit() != HCCL_SUCCESS) {
        HCCL_ERROR("DlHalFunction init failed!");
    }
}

CannErrorReporter::~CannErrorReporter()
{
    status2Event_.clear();
    void Clear();
}

CannErrorReporter& CannErrorReporter::GetInstance()
{
    static CannErrorReporter instance;
    return instance;
}

HcclResult CannErrorReporter::Init(uint32_t deviceId)
{
    if (sensorHandle_ != DEFAULT_SENSOR_HANDLE && devId_ == deviceId) {
        return HCCL_SUCCESS;
    }

    if (sensorHandle_ != DEFAULT_SENSOR_HANDLE) {
        void Clear();
    }

    CHK_PRT_RET(RegisterSensorNode(deviceId, &sensorHandle_) != HCCL_SUCCESS,
        HCCL_RUN_WARNING("[CannErrorReporter][Init] init sensor node fail, deviceId[%u].",
        deviceId), HCCL_E_INTERNAL);
    devId_ = deviceId;
    return HCCL_SUCCESS;
}

HcclResult CannErrorReporter::Clear()
{
    if (sensorHandle_ != DEFAULT_SENSOR_HANDLE) {
        HcclResult ret = UnRegisterSensorNode(devId_, sensorHandle_);
        if (ret != HCCL_SUCCESS) {
            HCCL_RUN_WARNING("[CannErrorReporter][Clear] unregister sensor node fail, handle[%llu], deviceId[%u].",
                sensorHandle_, devId_);
        } else {
            HCCL_INFO("[CannErrorReporter][Clear] unregister sensor node success, handle[%llu], devId[%u].",
                sensorHandle_, devId_);
        }
    }
    sensorHandle_ = DEFAULT_SENSOR_HANDLE;
    devId_ = 0;
    return HCCL_SUCCESS;
}

HcclResult CannErrorReporter::UpdateSensorNode(uint32_t deviceId, ReportStatus reportStatus)
{
    if (sensorHandle_ == DEFAULT_SENSOR_HANDLE || devId_ != deviceId) {
        CHK_PRT_RET(Init(deviceId) != HCCL_SUCCESS,
            HCCL_RUN_WARNING("[CannErrorReporter][UpdateSensorNode] fail to get a valid node sensor."),
            HCCL_E_INTERNAL);
    }
    uint64_t handle = sensorHandle_;

    auto iter = status2Event_.find(reportStatus);
    if (iter == status2Event_.end()) {
        HCCL_RUN_WARNING("[CannErrorReporter][UpdateSensorNode] "
            "unknown reportStatus[%u], fail to find corresponding event type, update node sensor fail.",
            reportStatus);
        return HCCL_E_NOT_SUPPORT;
    }
    int32_t eventType = static_cast<int32_t>(iter->second.first);
    halGeneralEventType_t eventAssert = iter->second.second;

    HCCL_INFO("[CannErrorReporter][UpdateSensorNode]updating sensor, "
        "deviceId[%u], reportStatus[%u], event val[%u], event assert[%u].",
        deviceId, reportStatus, eventType, eventAssert);

    CHK_PRT_RET(hrtHalSensorNodeUpdateState(deviceId, handle, eventType, eventAssert) != HCCL_SUCCESS,
        HCCL_RUN_WARNING("[CannErrorReporter][UpdateSensorNode] "
            "update sensor node fail, deviceId[%u], reportStatus[%u], val[%d], handle[%llu].",
            deviceId, reportStatus, eventType, handle),
        HCCL_E_INTERNAL);

    HCCL_RUN_INFO("[CannErrorReporter][UpdateSensorNode] send report success, "
        "deviceId[%u], reportStatus[%u], val[%d], handle[%llu].",
        deviceId, reportStatus, eventType, handle);
    return HCCL_SUCCESS;
}

HcclResult CannErrorReporter::ConstructSensorNodeCfg(halSensorNodeCfg &cfg)
{
    cfg.NodeType = HAL_DMS_DEV_TYPE_HCCP;
    cfg.SensorType = SAFTY_STATE_SENSOR_TYTPE;
    cfg.AssertEventMask = HCCL_ASSERT_EVENT_MASK;
    cfg.DeassertEventMask = HCCL_DEASSERT_EVENT_MASK;

    auto const ret = snprintf_s(cfg.name, sizeof(cfg.name), sizeof(cfg.name) - 1U, "hccl_%d", getpid());
    if (ret <= 0) {
        HCCL_ERROR("[CannErrorReporter][ConstructSensorNodeCfg] sprintf_s name err, ret[%d].", ret);
        return HCCL_E_INTERNAL;
    }

    return HCCL_SUCCESS;
}

HcclResult CannErrorReporter::RegisterSensorNode(uint32_t deviceId, uint64_t *handle)
{
    halSensorNodeCfg cfg = { 0 };
    CHK_PRT_RET(ConstructSensorNodeCfg(cfg) != HCCL_SUCCESS,
        HCCL_ERROR("[CannErrorReporter][RegisterSensorNode] fail to construct node cfg."),
        HCCL_E_INTERNAL);

    HcclResult ret = hrtHalSensorNodeRegister(deviceId, &cfg, handle);
    CHK_PRT_RET(ret != HCCL_SUCCESS,
        HCCL_RUN_WARNING("[CannErrorReporter][RegisterSensorNode] register sensor node fail, device id[%u].", deviceId),
        HCCL_E_INTERNAL);

    HCCL_INFO("[CannErrorReporter][RegisterSensorNode] register node sensor success, deviceId[%u], handle[%llu].",
        deviceId, *handle);
    return HCCL_SUCCESS;
}

HcclResult CannErrorReporter::UnRegisterSensorNode(uint32_t deviceId, uint64_t handle)
{
    HcclResult ret = hrtHalSensorNodeUnregister(deviceId, handle);
    CHK_PRT_RET(ret != HCCL_SUCCESS,
        HCCL_RUN_WARNING("[CannErrorReporter][UnRegisterSensorNode] "
        "unregister sensor node fail, device id[%u], handle[%llu].", deviceId, handle), HCCL_E_INTERNAL);
    HCCL_INFO("[CannErrorReporter][UpdateSensorNode]unregister sensor success, device id[%u], handle[%llu].",
        deviceId, handle);

    return HCCL_SUCCESS;
}

} // namespace
